package ChannelTutorial.Demo03;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;

/**
 * Demo03 - ChannelPipeline 和 ChannelHandler 详解 - 服务端
 * 
 * 学习目标：
 * 1. 理解 ChannelPipeline 的概念和作用
 * 2. 掌握 ChannelHandler 的类型（Inbound 和 Outbound）
 * 3. 理解数据在 Pipeline 中的流向
 * 4. 学习如何动态添加和移除 Handler
 * 5. 掌握 ChannelHandlerContext 的使用
 */
@Slf4j
public class Server {

    public static void main(String[] args) throws Exception {
        log.info("=== ChannelPipeline 和 ChannelHandler 详解 ===\n");
        
        EventLoopGroup boss = new NioEventLoopGroup(1);
        EventLoopGroup worker = new NioEventLoopGroup();
        
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        log.info("\n=== 新连接建立，初始化 Pipeline ===\n");
                        
                        ChannelPipeline pipeline = ch.pipeline();
                        
                        // 添加多个 Handler 到 Pipeline
                        // 注意：添加顺序很重要！
                        
                        // Inbound Handlers（处理接收到的数据）
                        pipeline.addLast("inbound1", new InboundHandler1());
                        pipeline.addLast("inbound2", new InboundHandler2());
                        pipeline.addLast("inbound3", new InboundHandler3());
                        
                        // Outbound Handlers（处理发送的数据）
                        pipeline.addLast("outbound1", new OutboundHandler1());
                        pipeline.addLast("outbound2", new OutboundHandler2());
                        pipeline.addLast("outbound3", new OutboundHandler3());
                        
                        // 业务处理 Handler
                        pipeline.addLast("business", new BusinessHandler());
                        
                        // 打印 Pipeline 结构
                        printPipelineStructure(pipeline);
                    }
                });
            
            ChannelFuture bindFuture = serverBootstrap.bind(8080).sync();
            log.info("服务端启动成功，监听端口 8080");
            log.info("使用 telnet localhost 8080 或 nc localhost 8080 连接测试\n");
            log.info("发送任意消息测试 Pipeline 的数据流向\n");
            
            bindFuture.channel().closeFuture().sync();
            
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

    /**
     * 打印 Pipeline 结构
     */
    private static void printPipelineStructure(ChannelPipeline pipeline) {
        log.info("┌─────────────────────────────────────────");
        log.info("│ Pipeline 结构：");
        log.info("│");
        
        pipeline.forEach(entry -> {
            log.info("│ → {}", entry.getKey());
        });
        
        log.info("│");
        log.info("└─────────────────────────────────────────\n");
    }

    /**
     * Inbound Handler 1
     * 
     * InboundHandler 处理入站事件（数据从网络流向应用）
     * 执行顺序：按照添加到 Pipeline 的顺序执行
     */
    @Slf4j
    @ChannelHandler.Sharable
    static class InboundHandler1 extends ChannelInboundHandlerAdapter {
        
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            log.info("📥 [Inbound1] channelActive - 连接激活");
            // 传递给下一个 Handler
            ctx.fireChannelActive();
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            log.info("📥 [Inbound1] channelRead - 开始处理");
            
            ByteBuf buf = (ByteBuf) msg;
            String data = buf.toString(StandardCharsets.UTF_8);
            log.info("   [Inbound1] 收到原始数据: {}", data);
            
            // 数据预处理：去除前后空格
            String processed = data.trim();
            log.info("   [Inbound1] 处理后数据: {}", processed);
            
            // 传递给下一个 Handler
            ctx.fireChannelRead(Unpooled.copiedBuffer(processed, StandardCharsets.UTF_8));
            
            // 释放原始 ByteBuf
            buf.release();
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            log.info("📥 [Inbound1] channelInactive - 连接断开");
            ctx.fireChannelInactive();
        }
    }

    /**
     * Inbound Handler 2
     */
    @Slf4j
    @ChannelHandler.Sharable
    static class InboundHandler2 extends ChannelInboundHandlerAdapter {
        
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            log.info("📥 [Inbound2] channelActive - 连接激活");
            ctx.fireChannelActive();
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            log.info("📥 [Inbound2] channelRead - 开始处理");
            
            ByteBuf buf = (ByteBuf) msg;
            String data = buf.toString(StandardCharsets.UTF_8);
            log.info("   [Inbound2] 收到数据: {}", data);
            
            // 数据转换：转为大写
            String processed = data.toUpperCase();
            log.info("   [Inbound2] 转换为大写: {}", processed);
            
            // 传递给下一个 Handler
            ctx.fireChannelRead(Unpooled.copiedBuffer(processed, StandardCharsets.UTF_8));
            
            buf.release();
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            log.info("📥 [Inbound2] channelInactive - 连接断开");
            ctx.fireChannelInactive();
        }
    }

    /**
     * Inbound Handler 3
     */
    @Slf4j
    @ChannelHandler.Sharable
    static class InboundHandler3 extends ChannelInboundHandlerAdapter {
        
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            log.info("📥 [Inbound3] channelActive - 连接激活");
            ctx.fireChannelActive();
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            log.info("📥 [Inbound3] channelRead - 开始处理");
            
            ByteBuf buf = (ByteBuf) msg;
            String data = buf.toString(StandardCharsets.UTF_8);
            log.info("   [Inbound3] 收到数据: {}", data);
            
            // 添加前缀
            String processed = "[PROCESSED] " + data;
            log.info("   [Inbound3] 添加前缀: {}", processed);
            
            // 传递给下一个 Handler
            ctx.fireChannelRead(Unpooled.copiedBuffer(processed, StandardCharsets.UTF_8));
            
            buf.release();
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            log.info("📥 [Inbound3] channelInactive - 连接断开");
            ctx.fireChannelInactive();
        }
    }

    /**
     * Outbound Handler 1
     * 
     * OutboundHandler 处理出站事件（数据从应用流向网络）
     * 执行顺序：按照添加到 Pipeline 的逆序执行
     */
    @Slf4j
    @ChannelHandler.Sharable
    static class OutboundHandler1 extends ChannelOutboundHandlerAdapter {
        
        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) 
                throws Exception {
            log.info("📤 [Outbound1] write - 开始处理");
            
            ByteBuf buf = (ByteBuf) msg;
            String data = buf.toString(StandardCharsets.UTF_8);
            log.info("   [Outbound1] 准备发送: {}", data);
            
            // 添加时间戳
            String processed = data + " [" + System.currentTimeMillis() + "]";
            log.info("   [Outbound1] 添加时间戳: {}", processed);
            
            // 传递给下一个 Handler（注意是 ctx.write，不是 fireWrite）
            ctx.write(Unpooled.copiedBuffer(processed, StandardCharsets.UTF_8), promise);
            
            buf.release();
        }
    }

    /**
     * Outbound Handler 2
     */
    @Slf4j
    @ChannelHandler.Sharable
    static class OutboundHandler2 extends ChannelOutboundHandlerAdapter {
        
        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) 
                throws Exception {
            log.info("📤 [Outbound2] write - 开始处理");
            
            ByteBuf buf = (ByteBuf) msg;
            String data = buf.toString(StandardCharsets.UTF_8);
            log.info("   [Outbound2] 准备发送: {}", data);
            
            // 添加换行符
            String processed = data + "\n";
            log.info("   [Outbound2] 添加换行符");
            
            ctx.write(Unpooled.copiedBuffer(processed, StandardCharsets.UTF_8), promise);
            
            buf.release();
        }
    }

    /**
     * Outbound Handler 3
     */
    @Slf4j
    @ChannelHandler.Sharable
    static class OutboundHandler3 extends ChannelOutboundHandlerAdapter {
        
        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) 
                throws Exception {
            log.info("📤 [Outbound3] write - 开始处理（最后一个 OutboundHandler）");
            
            ByteBuf buf = (ByteBuf) msg;
            String data = buf.toString(StandardCharsets.UTF_8);
            log.info("   [Outbound3] 最终发送的数据: {}", data);
            
            // 传递给网络层
            ctx.write(msg, promise);
        }
    }

    /**
     * 业务处理 Handler
     * 
     * 这个 Handler 既处理入站事件，也触发出站事件
     */
    @Slf4j
    @ChannelHandler.Sharable
    static class BusinessHandler extends ChannelInboundHandlerAdapter {
        
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            log.info("💼 [Business] channelActive - 连接建立，发送欢迎消息");
            
            // 触发出站事件：发送欢迎消息
            ctx.writeAndFlush(
                Unpooled.copiedBuffer("Welcome to Netty Pipeline Demo!", StandardCharsets.UTF_8)
            );
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            log.info("💼 [Business] channelRead - 业务处理");
            
            ByteBuf buf = (ByteBuf) msg;
            String data = buf.toString(StandardCharsets.UTF_8);
            log.info("   [Business] 收到经过 Pipeline 处理的数据: {}", data);
            
            // 业务逻辑：生成响应
            String response = "Echo: " + data;
            log.info("   [Business] 生成响应: {}", response);
            
            // 触发出站事件：发送响应
            // 注意：这里的数据会经过 Outbound Handlers 处理
            ctx.writeAndFlush(
                Unpooled.copiedBuffer(response, StandardCharsets.UTF_8)
            );
            
            buf.release();
            
            // 演示不同的事件传播方式
            demonstrateEventPropagation(ctx);
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            log.info("💼 [Business] channelInactive - 连接断开");
            ctx.fireChannelInactive();
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            log.error("💼 [Business] exceptionCaught - 发生异常", cause);
            ctx.close();
        }

        /**
         * 演示不同的事件传播方式
         */
        private void demonstrateEventPropagation(ChannelHandlerContext ctx) {
            log.info("\n=== 演示事件传播方式 ===");
            
            // 方式 1: ctx.fireChannelRead(msg)
            // 从当前 Handler 的下一个 Handler 开始传播
            log.info("ctx.fireChannelRead() - 从下一个 Handler 开始传播（入站）");
            
            // 方式 2: ctx.channel().pipeline().fireChannelRead(msg)
            // 从 Pipeline 的第一个 Handler 开始传播
            log.info("pipeline.fireChannelRead() - 从第一个 Handler 开始传播（入站）");
            
            // 方式 3: ctx.write(msg)
            // 从当前 Handler 的前一个 Outbound Handler 开始传播
            log.info("ctx.write() - 从前一个 Outbound Handler 开始传播（出站）");
            
            // 方式 4: ctx.channel().write(msg)
            // 从 Pipeline 的最后一个 Outbound Handler 开始传播
            log.info("channel.write() - 从最后一个 Outbound Handler 开始传播（出站）");
            
            log.info("======================\n");
        }
    }
}

/*
=== 运行结果分析 ===

1. Pipeline 的结构：
   HeadContext → Handler1 → Handler2 → Handler3 → TailContext
   
2. 入站事件流向（Inbound）：
   网络 → Head → Inbound1 → Inbound2 → Inbound3 → Business → Tail
   
3. 出站事件流向（Outbound）：
   Business → Outbound3 → Outbound2 → Outbound1 → Head → 网络
   
   注意：Outbound Handler 的执行顺序是逆序！

4. 数据处理过程：
   入站：接收 "hello" 
       → Inbound1: 去空格 "hello"
       → Inbound2: 转大写 "HELLO"
       → Inbound3: 加前缀 "[PROCESSED] HELLO"
       → Business: 生成响应 "Echo: [PROCESSED] HELLO"
   
   出站：发送 "Echo: [PROCESSED] HELLO"
       → Outbound3: 准备发送
       → Outbound2: 加换行符
       → Outbound1: 加时间戳
       → 网络: 发送最终数据

5. ChannelHandlerContext 的作用：
   - 提供 Handler 和 Pipeline 之间的关联
   - 控制事件的传播方向
   - 提供读写数据的方法

=== 关键知识点 ===

1. Pipeline 是 Handler 的链表
2. 每个 Channel 都有一个 Pipeline
3. Inbound Handler 按添加顺序执行
4. Outbound Handler 按添加逆序执行
5. 使用 ctx.fireXXX() 传播入站事件
6. 使用 ctx.write() 传播出站事件
7. 使用 @Sharable 注解可以让 Handler 被多个 Pipeline 共享

=== 最佳实践 ===

✅ 合理划分 Handler 职责（解码、业务、编码）
✅ 使用有意义的 Handler 名称
✅ 入站 Handler 要调用 fireXXX() 传播事件
✅ 及时释放 ByteBuf（使用 release()）
✅ 在 exceptionCaught 中处理异常

❌ 不要在 Handler 中执行阻塞操作
❌ 不要忘记传播事件（会导致 Pipeline 中断）
❌ 不要重复释放 ByteBuf
*/

